package jef.tools.reflect;
import java.lang.reflect.Field;
import jef.tools.Assert;
import sun.misc.Unsafe;
/**
* 使用sun.misc.Unsafe进行一些特殊操作的工具类
*
* @author jiyi
*
*/
@SuppressWarnings("restriction")
public final class UnsafeUtils {
static sun.misc.Unsafe unsafe;
public static long stringoffset;
public static boolean enable=System.getProperty("disable.unsafe")==null;
static {
try {
Class<?> clazz = Class.forName("sun.misc.Unsafe");
Field field = clazz.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
java.lang.reflect.Field stringValue=String.class.getDeclaredField("value");
stringoffset=unsafe.objectFieldOffset(stringValue);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取Unsafe对象
* @return
*/
public final static sun.misc.Unsafe getUnsafe(){
return unsafe;
}
/**
* 不使用反射直接创造对象,注意类的构造方法不会被执行
* @param clz
* @return 被构造的对象
*/
@SuppressWarnings("unchecked")
public final static <T> T newInstance(Class<T> clz){
try {
return (T) unsafe.allocateInstance(clz);
} catch (InstantiationException e) {
throw new IllegalStateException(e.getCause());
}
}
/**
* 用指定的ClassLoader加载二进制数据为class
* @param className
* @param data
* @param i
* @param length
* @param classLoader
* @return
*/
public final static Class<?> defineClass(String className, byte[] data, int i, int length, ClassLoader classLoader) {
if(data==null || data.length==0){
throw new IllegalArgumentException("the input class data is empty!");
}
if(length<1 || i+length<data.length){
throw new IllegalArgumentException("the input length is invalid!");
}
if(className==null || className.length()==0){
throw new IllegalArgumentException("the class name is invalid!"+className);
}
Assert.notNull(classLoader);
// LogUtil.debug("Unsafe load class ["+className+"] to "+classLoader);
return unsafe.defineClass(className, data, i, length, classLoader, null);
}
/**
* 返回String对象中的char[]数组。<br>
* 修改String 中的char[]是十分危险的,尤其是当被修改的char[]是属于常量池的String时,会发生十分难以检测的,不可预期的问题。
* <p>
* 因此这个方法用来:
* 1、获取String中的char[],用于读取和遍历。
* 2、只有当非常确信String所引用的char[]不在常量池中时,可以进行修改。如果一个常量string进行substring操作,会产生的一个不完全对象的String。
* 这个string的char[]引用上一个string的char[],因此只有确信string对象是通过拼接等方式重新生成时,才能使用此方法
*
* <p>
* 这个方法的意义所在:
* string.toCharArray();方法和这个很相似,但是性能上要稍微差一点。这个差别非常小。
* 以长度为8的string来测试,运行一万次,toCharArray耗时3000us(当string比较大时可能更慢),调用这个方法耗时约1000us(由于不用创建新对象)。
* <p>
* 实际测试发现,通过toCharArray来遍历对象要比下面的方法更耗时。
* for(int j=0;j<s.length();j++){
* char c=s.charAt(j);
* }
* 而这种方式和unsafe的方式其实耗时差距不大。
*
* @param str
* @return
*/
public final static char[] getValue(String str){
return (char[])unsafe.getObject(str, stringoffset);
}
}